// FleetView.cs
//
// Copyright (c) 2007 Mike Strobel
//
// This source code is subject to the terms of the Microsoft Reciprocal License (Ms-RL).
// For details, see <http://www.opensource.org/licenses/ms-rl.html>.
//
// All other rights reserved.

using System;
using System.Collections.Generic;
using System.Linq;

using Supremacy.Collections;
using Supremacy.Entities;
using Supremacy.Game;

namespace Supremacy.Orbitals
{
    [Serializable]
    public sealed class FleetView : IEquatable<FleetView>
    {
        #region Fields
        private bool _isOwned;
        private bool _isOwnerKnown;
        private bool _isPresenceKnown;
        private ArrayWrapper<ShipView> _ships;
        private int _sourceId;
        #endregion

        #region Constructors and Finalizers
        private FleetView() {}
        #endregion

        #region Properties and Indexers
        public bool IsDesignOfShipsKnown
        {
            get { return _ships.All(ship => ship.IsDesignKnown); }
        }

        public bool IsNumberOfShipsKnown
        {
            get { return _ships.All(ship => ship.IsPresenceKnown); }
        }

        public bool IsOwned
        {
            get { return _isOwned; }
        }

        public bool IsOwnerKnown
        {
            get { return _isOwnerKnown; }
        }

        public bool IsPresenceKnown
        {
            get { return _isPresenceKnown; }
        }

        public string Name
        {
            get
            {
                if (IsOwned || IsDesignOfShipsKnown)
                    return Source.Name;
                if (IsNumberOfShipsKnown)
                    return _ships.Count + " Cloaked Ship(s)";
                if (IsOwnerKnown)
                {
                    string ownerName = Source.Owner.ShortName;
                    if (ownerName.EndsWith("s"))
                        ownerName = ownerName.Substring(0, ownerName.Length - 1);
                    return ownerName + " Fleet";
                }
                return "Unknown Fleet";
            }
        }

        public IIndexedCollection<ShipView> Ships
        {
            get { return _ships; }
        }

        public Fleet Source
        {
            get { return GameContext.Current.Universe.Get<Fleet>(_sourceId); }
        }
        #endregion

        #region Public and Protected Methods
        public static FleetView Create(Civilization owner, Fleet fleet)
        {
            if (owner == null)
                throw new ArgumentNullException("owner");
            if (fleet == null)
                throw new ArgumentNullException("fleet");

            var ships = new List<ShipView>();
            var fleetView = new FleetView
                            {
                                _sourceId = fleet.ObjectID,
                                _isOwned = (fleet.OwnerID == owner.CivID)
                            };

            if (fleet.IsCloaked && (fleet.OwnerID != owner.CivID))
            {
                CivilizationManager civManager = GameContext.Current.CivilizationManagers[owner];

                int cloakStrength = 0;
                int scanStrength = civManager.MapData.GetScanStrength(fleet.Location);

                foreach (Ship ship in fleet.Ships)
                {
                    bool isPresenceKnown = false;
                    bool isDesignKnown = false;
                    if (ship.IsCloaked)
                    {
                        if ((cloakStrength == 0) || (ship.CloakStrength < cloakStrength))
                            cloakStrength = ship.CloakStrength;

                        if ((scanStrength - ship.CloakStrength) >= -1)
                            fleetView._isPresenceKnown = true;

                        if ((scanStrength - ship.CloakStrength) >= 0)
                        {
                            isPresenceKnown = true;
                            fleetView._isOwnerKnown = true;
                        }

                        if ((scanStrength - ship.CloakStrength) >= 1)
                            isDesignKnown = true;
                    }
                    else
                    {
                        fleetView._isOwnerKnown = true;
                        fleetView._isPresenceKnown = true;
                        isPresenceKnown = true;
                        isDesignKnown = true;
                    }

                    ships.Add(
                        new ShipView(
                            ship,
                            isPresenceKnown,
                            isDesignKnown,
                            fleetView._isOwned));
                }
            }
            else
            {
                fleetView._isOwnerKnown = true;
                fleetView._isPresenceKnown = true;

                ships.AddRange(
                    fleet.Ships.Select(
                        ship => new ShipView(
                                    source: ship,
                                    isPresenceKnown: true,
                                    isDesignKnown: true,
                                    isOwned: fleetView._isOwned)));
            }

            fleetView._ships = new ArrayWrapper<ShipView>(ships.ToArray());

            return fleetView;
        }

        public override bool Equals(object obj)
        {
            return Equals(obj as FleetView);
        }

        public override int GetHashCode()
        {
            return _sourceId;
        }
        #endregion

        #region Implementation of IEquatable<FleetView>
        public bool Equals(FleetView other)
        {
            if (ReferenceEquals(other, null))
                return false;
            return (other._sourceId == this._sourceId);
        }
        #endregion
    }

    [Serializable]
    public sealed class ShipView : IEquatable<ShipView>
    {
        #region Fields
        private readonly bool _isDesignKnown;
        private readonly bool _isOwned;
        private readonly bool _isPresenceKnown;
        private readonly int _sourceId;
        #endregion

        #region Constructors and Finalizers
        public ShipView(
            // ReSharper disable SuggestBaseTypeForParameter
            Ship source,
            // ReSharper restore SuggestBaseTypeForParameter
            bool isPresenceKnown,
            bool isDesignKnown,
            bool isOwned)
        {
            if (source == null)
                throw new ArgumentNullException("source");
            _sourceId = source.ObjectID;
            _isPresenceKnown = isPresenceKnown;
            _isDesignKnown = isDesignKnown;
            _isOwned = isOwned;
        }
        #endregion

        #region Properties and Indexers
        public bool IsDesignKnown
        {
            get { return _isDesignKnown; }
        }

        public bool IsOwned
        {
            get { return _isOwned; }
        }

        public bool IsPresenceKnown
        {
            get { return _isPresenceKnown; }
        }

        public Ship Source
        {
            get { return GameContext.Current.Universe.Get<Ship>(_sourceId); }
        }
        #endregion

        #region Public and Protected Methods
        public override bool Equals(object obj)
        {
            return Equals(obj as ShipView);
        }

        public override int GetHashCode()
        {
            return _sourceId;
        }
        #endregion

        #region Implementation of IEquatable<ShipView>
        public bool Equals(ShipView other)
        {
            if (ReferenceEquals(other, null))
                return false;
            return (other._sourceId == this._sourceId);
        }
        #endregion
    }
}